package org.opsli.modulars.weChatMp;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import org.opsli.api.base.result.ResultWrapper;
import org.opsli.api.web.system.user.UserApi;
import org.opsli.api.wrapper.system.user.UserInfo;
import org.opsli.api.wrapper.system.user.UserModel;
import org.opsli.common.annotation.Limiter;
import org.opsli.common.exception.ServiceException;
import org.opsli.common.utils.WrapperUtil;
import org.opsli.modulars.system.login.dto.LoginModel;
import org.opsli.modulars.system.login.handler.before.LoginModelVerifyCaptchaBeforeHandler;
import org.opsli.modulars.system.login.handler.before.LoginModelVerifyTempLockedBeforeHandler;
import org.opsli.modulars.system.login.handler.error.BizServiceErrorHandler;
import org.opsli.modulars.system.login.handler.success.*;
import org.opsli.plugins.security.authentication.WeChatOpenidAuthenticationToken;
import org.opsli.plugins.security.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.rmi.ServerException;


/**
 * 微信公众号登录相关控制器
 */
@Api(tags = "微信公众号登录相关控制器")
@Slf4j
@RestController
public class WeMpLoginRestController {
    /**
     * 小程序登录
     * @return ResultWrapper
     */
    @Autowired
    private WxMpService mpService;
    @ApiOperation(value = "微信公众号登录", notes = "微信公众号登录")
    @GetMapping("/weChatMp/login")
    public void getopenid(String code) {

        //使用前端传过来的code获取微信openId
        WxOAuth2AccessToken accessToken = null;
        try {
            accessToken = mpService.getOAuth2Service().getAccessToken(code);
        } catch (WxErrorException e) {
            throw new ServiceException(500,e.getMessage());
        }
        log.info("获取微信openid返回值为={}",accessToken.getOpenId());
        UserInfo userInfo= getUserInfo(accessToken.getOpenId());
//        return ResultWrapper.getSuccessResultWrapper(userInfo);
    }

    private LoginHandler<LoginModel> loginHandler;
    /**
     *  登陆方法
     *  @params encryptModel 非对称加密
     */


    @Autowired
    UserApi userApi;
    /**
     * 注册方法
     */
    private UserInfo register(String openId){
        //按照openid查询一次。有就返回去走登录。没有就注册并返回走登录
        String time = String.valueOf(System.currentTimeMillis());
        UserModel u = new UserModel();
        u.setCreateBy("0");
        u.setOpenid(openId);
        u.setRealName("微信用户");
        u.setTenantId("0");
        u.setUpdateBy("0");
        u.setIzManual(true);
        u.setIzTenantAdmin("0");
        u.setUsername(time);
        u.setPassword("Bb123456.");
        u.setEnableSwitchTenant("0");
        u.setNo(time);
        return WrapperUtil.transformInstance(userApi.insertWechat(u), UserInfo.class);
    }

    /**
     * 按照openid查询一次。有就返回去走登录。没有就注册并返回走登录
     */

    private UserInfo getUserInfo(String openId){
        UserInfo userInfo ;
        //按照openid查询一次。有就返回去走登录。没有就注册并返回走登录
        userInfo = userApi.getByOpenid(openId).getData();
        if (userInfo==null){
            //注册
            userInfo = register(openId);
        }

        //开始登录
        login(userInfo.getOpenid());
        return userInfo;
    }

    @Limiter
    public void login( String openid){
        // 验证加密登录对象

        // 转换模型
        LoginModel loginModel =new LoginModel();
        loginModel.setLoginFrom("4ru");
        loginModel.setPrincipal(openid);
        loginModel.setPassword("000");
        // 验证登录对象

        loginHandler.login(loginModel,
                model -> {
                    Authentication authentication = null;
                    String principal = loginModel.getPrincipal();
                    authentication = new WeChatOpenidAuthenticationToken(principal, model.getPassword());
                    return authentication;
                }
        );
    }


    /**
     *  初始化方法
     */
    @Autowired
    public void init(
            AuthenticationManager authenticationManager,
            LoginModelVerifyTempLockedBeforeHandler loginModelVerifyTempLockedBeforeHandler,
            LoginModelVerifyCaptchaBeforeHandler loginModelVerifyCaptchaBeforeHandler,
            LoginModelCreateAccessTokenHandler loginModelCreateAccessTokenHandler,
            LoginSuccessAfterVerifyHandler loginSuccessAfterVerifyHandler,
            LoginClearErrorSuccessHandler loginClearErrorSuccessHandler,
            LoginModelClearCaptchaSuccessHandler loginModelClearCaptchaSuccessHandler,
            LoginSuccessLogHandler loginSuccessLogHandler,
            AuthServiceErrorHandler authServiceErrorHandler,
            BizServiceErrorHandler bizServiceErrorHandler,
            OtherErrorHandler otherErrorHandler,
            AuthErrorHandler authErrorHandler,
            SecurityErrorHandler securityErrorHandler ){

        loginHandler = new LoginHandler.Builder<LoginModel>()
                .initAuthenticationManager(authenticationManager)
                .initLoginModelClass(LoginModel.class)
                // 前置处理器
                .before()
                // 验证账号是否临时冻结
                .addListener(loginModelVerifyTempLockedBeforeHandler)
                // 超过登陆失败次数 需要校验验证码
                .addListener(loginModelVerifyCaptchaBeforeHandler)
                .and()
                // 成功处理
                .accessSuccess()
                // 返回 记录登录日志信息
                .addListener(loginSuccessLogHandler)
                // 清除错误日志
                .addListener(loginClearErrorSuccessHandler)
                // 清除对应验证码信息
                .addListener(loginModelClearCaptchaSuccessHandler)
                // 登陆成功后 验证用户其他相关信息
                .addListener(loginSuccessAfterVerifyHandler)
                // 返回 accessToken
                .addListener(loginModelCreateAccessTokenHandler)
                .and()
                // 异常处理
                .accessDenied()
                // 增加认证服务异常处理器
                .addListener(authServiceErrorHandler)
                // 增加认证异常处理器
                .addListener(authErrorHandler)
                // 增加账户认证异常处理器
                .addListener(securityErrorHandler)
                // 增加内部业务异常处理器
                .addListener(bizServiceErrorHandler)
                // 增加其他未捕获异常处理器
                .addListener(otherErrorHandler)
                .and()
                .build();
    }

}




